package co.gov.medellin.sdep.sisdep.domain;

import java.util.Iterator;
import java.util.Map;

import javax.faces.FactoryFinder;
import javax.faces.application.Application;
import javax.faces.application.FacesMessage;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;

import co.gov.medellin.sdep.sisdep.common.AppConstants;

/**
 * <p>
 * Clase que encapsula metodos genericos para el uso en los Controllers.
 * </p>
 * <p>
 * Copyright (c) 2011<BR>
 * Consult-Soft S.A.<BR>
 * Created on: Nov 3, 2011<BR>
 * 
 * @author atabares
 * </p>
 */
public abstract class FacesController {

  /**
   * Constructor Vacio.
   */
  public FacesController() {
  }

  /**
   * @return Retorna el objeto aplicacion del FacesContext.
   */
  protected Application getApplication() {
    return FacesContext.getCurrentInstance().getApplication();
  }

  /**
   * @return Retorna el ApplicationMap en donde se almacenan objetos comunes en el ambito de aplicacion.
   */
  protected Map getApplicationMap() {
    return getExternalContext().getApplicationMap();
  }

  /**
   * @return Contexto Externo del Faces Context.
   */
  protected static final ExternalContext getExternalContext() {
    return FacesContext.getCurrentInstance().getExternalContext();
  }

  /**
   * @return El contexto de Faces.
   */
  protected FacesContext getFacesContext() {
    return FacesContext.getCurrentInstance();
  }

  /**
   * @return Retorna el ciclo actual en donde se encuentra el proceso.
   */
  protected Lifecycle getLifecycle() {
    String lifecycleId = getExternalContext().getInitParameter("javax.faces.LIFECYCLE_ID");
    if (lifecycleId == null || lifecycleId.length() == 0) {
      lifecycleId = "DEFAULT";
    }
    LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
        .getFactory("javax.faces.lifecycle.LifecycleFactory");
    return lifecycleFactory.getLifecycle(lifecycleId);
  }

  /**
   * @return Retorna el RequestMap en donde se almacenan los valores del request actual.
   */
  protected Map getRequestMap() {
    return getExternalContext().getRequestMap();
  }

  /**
   * @return Retorna el SessionMap en donde se almacenan objetos en el ambito de sesion.
   */
  protected static final Map getSessionMap() {
    return getExternalContext().getSessionMap();
  }

  /**
   * @param name Nombre del Bean.
   * @return Retorna el bean que tenga el nombe <code>name</code>.
   */
  protected Object getBean(String name) {
    return getApplication().getVariableResolver().resolveVariable(getFacesContext(), name);
  }

  /**
   * @param name Nombre del bean.
   * @param value Objeto a ser guardado como bean.
   */
  protected void setBean(String name, Object value) {
    setValue("#{" + name + "}", value);
  }

  /**
   * @param expr Expresion que representa un valor, puede ser de la forma #{bean.value}.
   * @return Objeto representado por expr.
   */
  protected Object getValue(String expr) {
    ValueBinding vb = getApplication().createValueBinding(expr);
    return vb.getValue(getFacesContext());
  }

  /**
   * @param expr Expresion que representa un valor, puede ser de la forma #{bean.value}.
   * @param value Valor de
   */
  protected void setValue(String expr, Object value) {
    ValueBinding vb = getApplication().createValueBinding(expr);
    vb.setValue(getFacesContext(), value);
  }

  /**
   * Borra el bean Acual.
   */
  protected void erase() {
    erase(((UIComponent) (getFacesContext().getViewRoot())));
  }

  /**
   * @param component Componente a ser borrado.
   */
  private void erase(UIComponent component) {
    if (component instanceof EditableValueHolder) {
      ((EditableValueHolder) component).setSubmittedValue(null);
    }
    for (Iterator kids = component.getFacetsAndChildren(); kids.hasNext();) {
      erase((UIComponent) kids.next());
    }
  }

  /**
   * Escribe un mensaje de log en el objeto aplicacion.
   * @param message Mensaje a ser guardado el log.
   */
  protected void log(String message) {
    getExternalContext().log(message);
  }

  /**
   * Escribe un mensaje de log en el objeto aplicacion.
   * @param message Mensaje a ser guardado el log.
   * @param throwable Excepcion a ser logueada.
   */
  protected void log(String message, Throwable throwable) {
    getExternalContext().log(message, throwable);
  }

  /**
   * Muestra un mensaje de informacion.
   * @param summary Mensaje de informacion a ser mostrado en la pagina actual.
   */
  protected void info(String summary) {
    getFacesContext().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, summary, null));
  }

  /**
   * Muestra un mensaje de informacion relacionado a un componente (Control).
   * @param component Componente a mostrasele el mensaje de informacion.
   * @param summary Mensaje de informacion.
   */
  protected void info(UIComponent component, String summary) {
    getFacesContext().addMessage(component.getClientId(getFacesContext()),
        new FacesMessage(FacesMessage.SEVERITY_INFO, summary, null));
  }

  /**
   * Muestra un mensaje de Alerta.
   * @param summary Mensaje de Alerta a ser mostrado en la pagina actual.
   */
  protected void warn(String summary) {
    getFacesContext().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, summary, null));
  }

  /**
   * Muestra un mensaje de alerta relacionado a un componente (Control).
   * @param component Componente a mostrasele el mensaje de alerta.
   * @param summary Mensaje de alerta.
   */
  protected void warn(UIComponent component, String summary) {
    getFacesContext().addMessage(component.getClientId(getFacesContext()),
        new FacesMessage(FacesMessage.SEVERITY_WARN, summary, null));
  }

  /**
   * Muestra un mensaje de error.
   * @param summary Mensaje de error a ser mostrado en la pagina actual.
   */
  protected void error(String summary) {
    getFacesContext().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, summary, null));
  }

  /**
   * Muestra un mensaje de error relacionado a un componente (Control).
   * @param component Componente a mostrasele el mensaje de error.
   * @param summary Mensaje de error.
   */
  protected void error(UIComponent component, String summary) {
    getFacesContext().addMessage(component.getClientId(getFacesContext()),
        new FacesMessage(FacesMessage.SEVERITY_ERROR, summary, null));
  }

  /**
   * Muestra un mensaje fatal.
   * @param summary Mensaje fatal a ser mostrado en la pagina actual.
   */
  protected void fatal(String summary) {
    getFacesContext().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_FATAL, summary, null));
  }

  /**
   * Muestra un mensaje fatal relacionado a un componente (Control).
   * @param component Componente a mostrasele el mensaje fatal.
   * @param summary Mensaje fatal.
   */
  protected void fatal(UIComponent component, String summary) {
    getFacesContext().addMessage(component.getClientId(getFacesContext()),
        new FacesMessage(FacesMessage.SEVERITY_FATAL, summary, null));
  }
  
	/**
	 * Metodo que permite generar una instancia dinamicamente de un backingbean sin
	 * tener que usar una Expresion EL para inicializarlo en una JSF
	 * @param expr
	 * @return
	 */
	public static final Object getBeanInstance(String expr){
	    FacesContext context = FacesContext.getCurrentInstance();
	    Application app = context.getApplication();
	    ValueBinding binding = app.createValueBinding("#{" + expr + "}");
	    return binding.getValue(context);
	}
  
	//--------------------------------------------------------------------
	//--- Funcionalidades extraidas de un SessionController			init()
	//--------------------------------------------------------------------
	//--------------------------------------------------------------------
	//--- NOTA: Se eliminara del codigo src/ el SessionController
	//--------------------------------------------------------------------

	/**
	 * Elimina de la session el objeto identificado con la llave pasada como parametro.
	 */
	public void sessionObjectRelease(String key) {
		getSessionMap().remove(key);
	}

	/**
	 * @param key Llave con la cual se hara referencia al valor en el mapa de sesion.
	 * @return Objeto que se encuentra asociado a la llave enviada por
	 *         parametro.
	 */
	public static final Object getSessionObject(String key) {
		return getSessionMap().get(key);
	}

	/**
	 * Agrega un objeto a la session del usuario, se deben agregar los objetos
	 * que se necesiten mantener entre las diferentes paginas jsp.
	 * 
	 * @param key Llave con la cual se hara referencia al valor enviado por
	 *            parametro.
	 * @param value Valor asociado a la llave especificada.
	 */
	public void setSessionObject(String key, Object value) {
		getSessionMap().put(key, value);
	}
	
	/**
	 * Metodo que permite obtener el ID del usuario autenticado en el Portal SAP.
	 * @return El IDentificador el usuario autenticado en el Portal SAP
	 */
	public static final String getLoggedUserID() {
		return (String)getSessionObject(AppConstants.USER_ID_PORTAL_SAP);
	}
	
	//--------------------------------------------------------------------
	//--- Funcionalidades extraidas de un SessionController			 end()
	//--------------------------------------------------------------------

}
